mod meta;
use meta::{Ping, Comm};
mod keymgr;
use keymgr::{Set, Get, Del};
mod hash;
use hash::{Hset, Hget};

use redis_protocol::resp2::prelude::*;
use crate::prelude::*;

use lazy_static::lazy_static;
use std::collections::HashMap;
pub trait CommandService: Sync + Send{
    fn process(&self, s: &Arc<dyn StorageService>, param: Frame) -> Option<Frame> ;
}

pub struct Command{
    inner:  Arc<dyn StorageService>
}

lazy_static! {
    pub static ref EXECUTORS: HashMap<&'static str, Box<dyn CommandService>> = 
    {
        let mut htable: HashMap<&'static str, Box<dyn CommandService>> = HashMap::new();

        htable.insert("ping", Box::new(Ping()));
        htable.insert("set", Box::new(Set{}));
        htable.insert("get", Box::new(Get()));
        htable.insert("del", Box::new(Del()));
        htable.insert("command", Box::new(Comm()));
        htable.insert("hset", Box::new(Hset()));
        htable.insert("hget", Box::new(Hget()));
        htable
    };
}
impl Command{
    
    pub fn new<Store: StorageService>(s: Store) -> Self {
        Command {
            inner: Arc::new(s),
        }
    }
    pub fn clone(&self) -> Self {
        Command { 
            inner: Arc::clone(&self.inner)
        }
    }
    pub fn execute(&self, cmd: Frame) -> Option<Frame>
    {
        let mut p = FrameParser::new(cmd.clone()).unwrap(); 
        let command_name = p.next_string().map_err(|_e| KvErr::UNEXPECTED).unwrap();
        match EXECUTORS.get(command_name.to_lowercase().as_str()) {
            Some(executor) => executor.process(&self.inner, cmd),
            None => Some(FrameConstructor::err())
        }
    }
}


